<?php

namespace app\api\controller\xmwechat;

use app\common\controller\Frontend;
use app\common\library\xmwechat\payment\PartnerPayService;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\RuntimeException;
use EasyWeChat\Pay\Application;
use EasyWeChat\Pay\Message;
use think\facade\Db;
use think\facade\Log;
use think\Request;

/**
 * 合作伙伴（服务商模式支付）
 */
class PartnerPayment extends Frontend
{
    // 数组中的 pay、refunds 请在调试完成后删除，支付、退款接口需要登录
    protected array $noNeedLogin = ['pay', 'refunds', 'payNotify', 'refundsNotify'];

    protected array $partnerPaymentConfig;

    protected array $wechatPartnerConfig;

    public function initialize(): void
    {
        parent::initialize();
        $config                = config('xmwechat');
        $this->partnerPaymentConfig = $config['partnerPayment'];

        $this->wechatPartnerConfig = [
            'mch_id'      => $this->partnerPaymentConfig['sp_mchid'],
            'secret_key'  => $this->partnerPaymentConfig['secret_key'],
            'certificate' => $this->partnerPaymentConfig['certificate'],
            'private_key' => $this->partnerPaymentConfig['sp_mchid'],
            'notify_url'  => $this->partnerPaymentConfig['notify_url'],
            'http'        => [
                'throw'   => true, // 状态码非 200、300 时是否抛出异常，默认为开启
                'timeout' => 5.0,
            ],
        ];
    }

    /**
     * 微信公众号、小程序支付示例（合作伙伴服务商模式）
     * 支付接口是需要登录的，测试结束后，请在最上方$noNeedLogin数组中去掉 pay
     * @param Request $request
     * @return void
     * @throws \Exception
     * @author jsjxsz <QQ:1365962177>
     * order_no 订单号
     * body 描述
     * pay_price 支付金额
     * openid 用户openid
     * transaction_no 交易号
     */
    public function pay(Request $request): void
    {
        if ($request->isPost()) {
            $params = $request->only(['order_no', 'body', 'pay_price', 'openid', 'transaction_no']);
            // miniProgram: 小程序支付； offiAccount： 公众号支付
            $params['pay_type'] = 'miniProgram';
            $result = PartnerPayService::getInstance()->pay($params);
            if ($result !== false) {
                $this->success('success', $result);
            } else {
                $this->error('error');
            }
        }
    }

    /**
     * 退款申请（退款状态需在退款回调中获取）
     * @param Request $request
     * @return void
     * @author jsjxsz <QQ:1365962177>
     * out_trade_no 原支付交易对应的商户订单号
     * out_refund_no 商户退款单号，商户系统内部的退款单号，退款时生成，唯一
     * reason 退款原因
     * refund_price 退款金额
     * pay_price 原交易金额
     */
    public function refunds(Request $request): void
    {
        if ($request->isPost()) {
            $params = $request->only(['pay_price', 'refund_price', 'out_trade_no','out_refund_no','reason']);
            $result = PartnerPayService::getInstance()->refunds($params);
            if ($result !== false) {
                $this->success('success', $result);
            } else {
                $this->error('error');
            }
        }
    }


    /**
     * 服务商模式支付回调
     * 注意仔细看下面的注释内容
     * @return \Psr\Http\Message\ResponseInterface|void
     * @author jsjxsz <QQ:1365962177>
     */
    public function payNotify()
    {
        try {
            $app    = new Application($this->wechatPartnerConfig);
            $server = $app->getServer();
            $server->handlePaid(function (Message $message, \Closure $next) use ($app) {
                $noyifyData   = json_decode($message, true);
                $success_time = strtotime($noyifyData['success_time']);
                $out_trade_no = $noyifyData['out_trade_no'];


                /**
                 * 这里写你自己的逻辑 start
                 */
                // 这里查询你自己的数据表！！！
                $order = Db::name('order')->where('transaction_no', $out_trade_no)->find();
                if (!$order || $order['pay_status'] == 1) {
                    // 如果订单不存在 或者 订单已经支付过了
                    // 告诉微信，我已经处理完了，订单没找到，别再通知我了
                    return ['code' => 'SUCCESS', 'message' => '成功'];
                }
                // return_code 表示通信状态，不代表支付状态
                if ($noyifyData['trade_state'] === 'SUCCESS') {
                    // pay success
                    $total_fee = $noyifyData['amount']['payer_total'] / 100;//单位分

                        // 这里写你自己的回调逻辑

                } elseif ($message['result_code'] === 'FAIL') {
                        // pay fail

                }
                /**
                 * 这里写你自己的逻辑 end
                 */

                return $next($message);
            });
            return $server->serve();
        } catch (InvalidArgumentException|RuntimeException|\ReflectionException|\Throwable $e) {
            Log::info('服务商微信支付回调通知：' . $e->getMessage());
        }
    }

    /**
     * 服务商模式退款回调
     * 注意仔细看下面的注释内容
     * @return \Psr\Http\Message\ResponseInterface|void
     * @author jsjxsz <QQ:1365962177>
     */
    public function refundsNotify()
    {
        try {
            $app    = new Application($this->wechatPartnerConfig);
            $server = $app->getServer();
            $server->handleRefunded(function (Message $message, \Closure $next) use ($app) {
                $noyifyData   = json_decode($message, true);
                $success_time = strtotime($noyifyData['success_time']); // 退款时间
                $out_refund_no = $noyifyData['out_refund_no'];

                /**
                 * 这里写你自己的逻辑 start
                 */
                // 这里查询你自己的数据表！！！
                $order_refunds = Db::name('order_refunds')->where('out_refund_no', $out_refund_no)->find();
                if (!$order_refunds || $order_refunds['refund_status'] == 1) {
                    // 如果订单不存在 或者 订单已经支付过了
                    // 告诉微信，我已经处理完了，订单没找到，别再通知我了
                    return ['code' => 'SUCCESS', 'message' => '成功'];
                }
                // return_code 表示通信状态，不代表支付状态
                if ($noyifyData['refund_status'] === 'SUCCESS') {
                    // success

                } elseif ($message['result_code'] === 'FAIL') {
                    // pay fail

                }
                /**
                 * 这里写你自己的逻辑 end
                 */

                return $next($message);
            });
            return $server->serve();
        } catch (InvalidArgumentException|RuntimeException|\ReflectionException|\Throwable $e) {
            Log::info('服务商微信退款回调通知：' . $e->getMessage());
        }
    }



}